// use postgres::NoTls;
use once_cell::sync::OnceCell;
use std::sync::mpsc::channel;
use std::sync::Arc;
#[allow(unused_must_use)]
use tokio_postgres::{Client, NoTls,Error};
use deadpool_postgres::{Manager, Pool, ManagerConfig, RecyclingMethod, ClientWrapper};
use deadpool::managed::Object;

// static DB:OnceCell<Arc<RwLock<Pool<PostgresConnectionManager<NoTls>>>>> = OnceCell::new();
pub static DB: OnceCell<Arc<Client>> = OnceCell::new();
pub static DBPOOL: OnceCell<Arc<Pool>> = OnceCell::new();

pub fn db_pool_init(pgurl:String, max:usize){
    let mgr_config = ManagerConfig {
        recycling_method: RecyclingMethod::Fast
    };
    let mgr = Manager::from_config(pgurl.parse().unwrap(), NoTls, mgr_config);
    // let mgr = Manager::from_config(pgurl.parse().unwrap(), NoTls,mgr_config);
    let pgpool = Pool::new(mgr,max);
    if let Err(_e) = DBPOOL.set(Arc::new(pgpool)){
        log_panic!("{}","数据库连接池设置失败");
    }
    log_info_ln!("{}", "数据库连接池初始化完毕");
}

pub async fn get_db_from_pool()-> Result<Object<ClientWrapper,Error>, String> {
    if let Some(s) = DBPOOL.get() {
        match s.get().await {
            Ok(o)=>{Ok(o)}
            Err(e)=>{Err(e.to_string())}
        }
    } else {
        Err("获取数据库句柄失败".to_string())
    }
}

pub fn db_init(pgurl: String, _max: u32) {
    let (sx, rx) = channel();
    tokio::spawn(async move {
        let (client, connection) = tokio_postgres::connect(&pgurl, NoTls)
            .await
            .expect("数据库连接错误");
        tokio::spawn(async move {
            if let Err(e) = connection.await {
                eprintln!("connection error: {}", e);
            }
        });
        std::thread::sleep(std::time::Duration::from_secs(1));
        sx.send(client).unwrap();
    });
    let client = rx
        .recv_timeout(std::time::Duration::from_secs(60))
        .expect("数据库连接失败");
    let res = DB.set(Arc::new(client));
    log_panic_result!(res);
    log_info_ln!("{}", "数据库连接成功");
}

pub fn get_db() -> Result<Arc<Client>, String> {
    if let Some(s) = DB.get() {
        Ok(Arc::clone(s))
    } else {
        Err("获取数据库句柄失败".to_string())
    }
}

#[macro_export]
macro_rules! db_exec {
    ($sx:expr,$query:expr,$flags:expr) => {
        log_debug_ln!("db exec: {}", $query.clone());
        tokio::spawn(async move {
            let client = match crate::app::module::db::get_db_from_pool().await {
                Err(e) => {
                    $sx.send(Err(e)).unwrap();
                    return;
                }
                Ok(o) => o,
            };
            match client.execute($query, $flags).await {
                Err(e) => {
                    log_debug_ln!("插入失败 {}", e.to_string());
                    $sx.send(Err(e.to_string())).unwrap();
                }
                Ok(o) => {
                    $sx.send(Ok(o)).unwrap();
                }
            }
        });
    };
}

#[macro_export]
macro_rules! db_query_one {
    ($sx:expr,$query:expr,$flags:expr) => {
        tokio::spawn(async move {
        log_debug_ln!("db exec: {}", $query.clone());
            let client = match crate::app::module::db::get_db_from_pool().await {
                Err(e) => {
                    $sx.send(Err(e)).unwrap();
                    return;
                }
                Ok(o) => o,
            };
            match client.query_one($query, $flags).await {
                Err(e) => {
                    log_debug_ln!("查询一条信息失败 {}", e.to_string());
                    $sx.send(Err(e.to_string())).unwrap();
                }
                Ok(o) => {
                    $sx.send(Ok(o)).unwrap();
                }
            }
        });
    };
}

//同步的方法，异步无法使用
// pub fn get_db()->Result<PooledConnection<PostgresConnectionManager<NoTls>>,String>{
//     if let Some(s)= DB.get(){
//         let pool_lock = Arc::clone(s);
//         let pool_lock_read = pool_lock.read();
//         match pool_lock_read {
//             Err(e)=>{Err(e.to_string())}
//             Ok(o)=>{
//                 let db = o.clone();
//                 match db.get() {
//                     Err(e)=>{Err(e.to_string())}
//                     Ok(o)=>{Ok(o)}
//                 }
//             }
//         }
//     }else { Err("获取数据库句柄失败".to_string())}
// }
